import tkinter as tk
from tkinter import filedialog, messagebox
try:
    import cv2
    print("OpenCV 导入成功，版本:", cv2.__version__)
except ImportError as e:
    print("错误：无法导入 OpenCV (cv2)。错误信息：", str(e))
    messagebox.showerror("错误", "无法导入 OpenCV，请确保正确安装了 opencv-python")
    exit(1)

try:
    import numpy as np
    print("NumPy 导入成功，版本:", np.__version__)
except ImportError as e:
    print("错误：无法导入 NumPy。错误信息：", str(e))
    messagebox.showerror("错误", "无法导入 NumPy，请确保正确安装了 numpy")
    exit(1)

try:
    import pyautogui
    print("PyAutoGUI 导入成功，版本:", pyautogui.__version__)
except ImportError as e:
    print("错误：无法导入 PyAutoGUI。错误信息：", str(e))
    messagebox.showerror("错误", "无法导入 PyAutoGUI，请确保正确安装了 pyautogui")
    exit(1)

from PIL import Image, ImageDraw
import time
from datetime import datetime
import os
import threading
import json

class ScreenRecorder:
    def __init__(self):
        try:
            self.root = tk.Tk()
            self.root.title("屏幕录制软件")
            self.root.geometry("300x100")
            self.root.resizable(False, False)

            # 配置文件路径
            self.config_file = "screen_recorder_config.json"
            self.save_path = self.load_last_path()  # 加载上次的路径
            self.is_recording = False
            self.recording_thread = None
            self.stop_event = threading.Event()

            # 创建鼠标指针图像
            self.cursor_size = 20
            self.cursor_color = (255, 0, 0)  # 红色
            self.cursor_img = self.create_cursor_image()

            # 创建按钮
            self.folder_btn = tk.Button(self.root, text="选择保存文件夹", command=self.select_folder)
            self.folder_btn.pack(side=tk.LEFT, padx=20, pady=20)

            self.record_btn = tk.Button(self.root, text="开始录制", command=self.toggle_recording)
            self.record_btn.pack(side=tk.RIGHT, padx=20, pady=20)

            # 如果有保存的路径，显示当前路径
            if self.save_path:
                self.show_current_path()
            
            print("GUI 初始化成功")
        except Exception as e:
            print("GUI 初始化失败：", str(e))
            messagebox.showerror("错误", f"GUI 初始化失败：{str(e)}")
            raise

    def create_cursor_image(self):
        """创建鼠标指针图像"""
        size = self.cursor_size
        img = Image.new('RGBA', (size, size), (0, 0, 0, 0))
        draw = ImageDraw.Draw(img)
        
        # 绘制鼠标指针（一个简单的箭头形状）
        points = [
            (0, 0),  # 顶点
            (size//2, size),  # 底部中点
            (size, 0),  # 右上角
            (0, 0)  # 回到顶点
        ]
        draw.line(points, fill=self.cursor_color, width=2)
        
        return np.array(img)

    def draw_cursor(self, frame):
        """在帧上绘制鼠标指针"""
        try:
            # 获取鼠标位置
            x, y = pyautogui.position()
            
            # 获取光标图像的尺寸
            cursor_h, cursor_w = self.cursor_img.shape[:2]
            
            # 计算光标的位置（确保不会超出边界）
            frame_h, frame_w = frame.shape[:2]
            x1 = max(0, min(x, frame_w - cursor_w))
            y1 = max(0, min(y, frame_h - cursor_h))
            x2 = min(x1 + cursor_w, frame_w)
            y2 = min(y1 + cursor_h, frame_h)
            
            # 在原始图像上绘制鼠标指针
            cursor_region = self.cursor_img[:y2-y1, :x2-x1]
            alpha_mask = cursor_region[:, :, 3] > 0
            
            if alpha_mask.size > 0:  # 确保有像素需要绘制
                frame[y1:y2, x1:x2][alpha_mask] = cursor_region[alpha_mask][:, :3]
            
        except Exception as e:
            print(f"绘制鼠标指针失败: {e}")
        
        return frame

    def load_last_path(self):
        """加载上次保存的路径"""
        try:
            if os.path.exists(self.config_file):
                with open(self.config_file, 'r', encoding='utf-8') as f:
                    config = json.load(f)
                    path = config.get('last_path', '')
                    if os.path.exists(path):  # 确认路径仍然存在
                        return path
        except Exception as e:
            print(f"加载配置文件失败: {e}")
        return ""

    def save_last_path(self):
        """保存当前路径到配置文件"""
        try:
            config = {'last_path': self.save_path}
            with open(self.config_file, 'w', encoding='utf-8') as f:
                json.dump(config, f, ensure_ascii=False)
        except Exception as e:
            print(f"保存配置文件失败: {e}")

    def show_current_path(self):
        """显示当前选择的路径"""
        if self.save_path:
            self.folder_btn.config(text="更改保存文件夹")
            self.root.title(f"屏幕录制软件 - {self.save_path}")

    def select_folder(self):
        try:
            # 如果已有路径，则从该路径开始选择
            initial_dir = self.save_path if self.save_path else "/"
            new_path = filedialog.askdirectory(initialdir=initial_dir)
            
            if new_path:
                self.save_path = new_path
                self.save_last_path()  # 保存新选择的路径
                self.show_current_path()  # 更新显示
                print(f"选择的保存路径: {self.save_path}")
                messagebox.showinfo("提示", f"已选择保存路径：{self.save_path}")
        except Exception as e:
            print("选择文件夹失败：", str(e))
            messagebox.showerror("错误", f"选择文件夹失败：{str(e)}")

    def toggle_recording(self):
        try:
            if not self.is_recording:
                if not self.save_path:
                    print("错误：未选择保存文件夹")
                    messagebox.showerror("错误", "请先选择保存文件夹！")
                    return
                
                self.start_recording()
                self.record_btn.config(text="停止录制")
                self.folder_btn.config(state=tk.DISABLED)
            else:
                self.stop_recording()
                self.record_btn.config(text="开始录制")
                self.folder_btn.config(state=tk.NORMAL)
        except Exception as e:
            print("录制切换失败：", str(e))
            messagebox.showerror("错误", f"录制切换失败：{str(e)}")

    def start_recording(self):
        try:
            self.is_recording = True
            self.stop_event.clear()  # 清除停止事件
            self.recording_thread = threading.Thread(target=self.record_screen)
            self.recording_thread.daemon = True  # 设置为守护线程
            self.recording_thread.start()
            print("开始录制")
        except Exception as e:
            print("开始录制失败：", str(e))
            messagebox.showerror("错误", f"开始录制失败：{str(e)}")
            self.is_recording = False

    def stop_recording(self):
        try:
            if self.is_recording:
                self.is_recording = False
                self.stop_event.set()  # 设置停止事件
                # 使用after方法来检查线程是否结束
                self.check_recording_stopped()
        except Exception as e:
            print("停止录制失败：", str(e))
            messagebox.showerror("错误", f"停止录制失败：{str(e)}")

    def check_recording_stopped(self):
        if self.recording_thread and self.recording_thread.is_alive():
            # 如果线程还在运行，100ms后再次检查
            self.root.after(100, self.check_recording_stopped)
        else:
            # 线程已结束，更新UI
            self.record_btn.config(text="开始录制")
            self.folder_btn.config(state=tk.NORMAL)
            print("停止录制")

    def record_screen(self):
        output_path = ""
        try:
            # 获取屏幕尺寸
            screen_width, screen_height = pyautogui.size()
            print(f"屏幕尺寸: {screen_width}x{screen_height}")
            
            # 生成输出文件名
            timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
            output_path = os.path.join(self.save_path, f"recording_{timestamp}.mp4")
            print(f"输出文件路径: {output_path}")
            
            # 创建视频写入器
            fourcc = cv2.VideoWriter_fourcc(*'mp4v')
            out = cv2.VideoWriter(output_path, fourcc, 20.0, (screen_width, screen_height))
            print("视频写入器初始化成功")

            while self.is_recording and not self.stop_event.is_set():
                # 截取屏幕
                screenshot = pyautogui.screenshot()
                frame = np.array(screenshot)
                frame = cv2.cvtColor(frame, cv2.COLOR_RGB2BGR)
                
                # 在帧上绘制鼠标指针
                frame = self.draw_cursor(frame)
                
                out.write(frame)
                time.sleep(0.05)  # 20 FPS
                
        except Exception as e:
            print("录制过程出错：", str(e))
            messagebox.showerror("错误", f"录制过程出错：{str(e)}")
        finally:
            if 'out' in locals():
                out.release()
            if output_path:
                print(f"录制完成，文件保存在：{output_path}")
                messagebox.showinfo("提示", f"录制完成！\n文件保存在：{output_path}")

    def run(self):
        try:
            print("启动应用程序")
            self.root.mainloop()
        except Exception as e:
            print("运行失败：", str(e))
            messagebox.showerror("错误", f"运行失败：{str(e)}")

if __name__ == "__main__":
    try:
        print("正在启动屏幕录制软件...")
        app = ScreenRecorder()
        app.run()
    except Exception as e:
        print("程序启动失败：", str(e))
        messagebox.showerror("错误", f"程序启动失败：{str(e)}") 